//go:build linux

package http_v3

import (
	"go2/log"
	"syscall"
)

func epoll_event(fd int32) *syscall.EpollEvent {
	return &syscall.EpollEvent{
		Fd: fd,
		// 判断是否连接异常事件
		// EPOLLIN: 描述符处于可读状态
		// EPOLLOUT: 描述符处于可写状态
		// EPOLLET: 将epoll event通知模式设置成edge triggered
		// EPOLLONESHOT: 第一次进行通知，之后不再监测
		// EPOLLHUP: 本端描述符产生一个挂断事件，默认监测事件
		// EPOLLRDHUP: 对端描述符产生一个挂断事件
		// EPOLLPRI: 由带外数据触发
		// EPOLLERR: 描述符产生错误时触发，默认检测事件
		Events: syscall.EPOLLIN | syscall.EPOLLERR | syscall.EPOLLRDHUP,
	}
}

func epoll_dell(epollFd int, fd int32) {
	//log.Debugf("epoll_dell fd: %d", fd)
	syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_DEL, int(fd), epoll_event(fd))
}

func epoll_add(epollFd int, fd int32) {
	//log.Debugf("epoll_add fd: %d", fd)
	syscall.EpollCtl(epollFd, syscall.EPOLL_CTL_ADD, int(fd), epoll_event(fd))
}

func epoll_init() (epollFd int, err error) {
	// epfd在这里表示epoll实例的文件描述符，它可以看作是红黑树的根节点，
	// 调用epoll_create(int size)的时候，在内核里面创建了一个红黑树和双链表，只不过是空的
	epollFd, err = syscall.EpollCreate1(0)
	if err != nil {
		log.Errorf("epoll create err: %v", err)
		return
	}
	log.Debugf("epoll create fd: %d", epollFd)
	return
}

func epoll_create_events(size int) []syscall.EpollEvent {
	return make([]syscall.EpollEvent, size)
}

func epoll_set_nonblock(fd int) error {
	return syscall.SetNonblock(fd, true)
}

func epoll_add_timer(epfd int, interval, value int64) (int, error) {
	// 创建定时器文件描述符
	timerFd, err := timerfdCreate(CLOCK_MONOTONIC, TFD_CLOEXEC)
	if err != nil {
		return -1, err
	}

	timerFd32 := int32(timerFd)

	// 设置定时器参数: 每Interval秒触发一次
	// 第一个Value秒后开始，之后每Interval秒触发一次
	timerSpec := itimerspec{
		Interval: syscall.NsecToTimeval(interval), // Interval秒间隔
		Value:    syscall.NsecToTimeval(value),    // Value秒后首次触发
	}
	if err = timerfdSettime(timerFd, 0, &timerSpec, nil); err != nil {
		return timerFd, err
	}

	// 将定时器文件描述符注册到epoll中
	ev := syscall.EpollEvent{
		Fd:     timerFd32,
		Events: syscall.EPOLLIN,
	}
	if err = syscall.EpollCtl(epfd, syscall.EPOLL_CTL_ADD, timerFd, &ev); err != nil {
		return timerFd, err
	}

	return timerFd, nil
}
